package com.ssish.saas.eccs.util;


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.TimeZone;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

/**
 * @Title:FTPUtil
 * @Description:
 * @Company:www.eshui.net 提供ftp 上传 下载 ，文件上传和下载需要优化downloadFile()
 *                        uploadDirectory()
 */
public class FtpUtil {
    private FTPClient ftpClient;
    private String IP;
    private int port;
    private String userName;
    private String password;
    private static final Log LOG = LogFactory.getLog(FtpUtil.class);

    /**
     * 构造函数
     * 
     * @param IP
     *            FTP服务器地址
     * @param userName
     *            FTP服务器用户名
     * @param passWord
     *            FTP服务器密码
     */
    public FtpUtil(String IP, int port, String userName, String password) {
        this.IP = IP;
        this.port = port;
        this.userName = userName;
        this.password = password;
        this.ftpClient = new FTPClient();
    }

    /**
     * @return 判断是否登入成功
     * */
    public boolean login() {
        boolean isLogin = false;
        FTPClientConfig ftpClientConfig = new FTPClientConfig();
        ftpClientConfig.setServerTimeZoneId(TimeZone.getDefault().getID());
        
        // this.ftpClient.setControlEncoding("GBK");
        this.ftpClient.configure(ftpClientConfig);
        
        try {
            if (this.port > 0) {
                this.ftpClient.connect(this.IP, this.port);
            } else {
                this.ftpClient.connect(IP);
            }
            // FTP服务器连接回答
            int reply = this.ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                this.ftpClient.disconnect();
                if (LOG.isDebugEnabled())
                    LOG.debug("登录FTP服务失败！");
                return isLogin;
            }
            this.ftpClient.login(this.userName, this.password);
            // 设置传输协议
//            this.ftpClient.enterLocalPassiveMode();
            this.ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            if (LOG.isDebugEnabled())
                LOG.debug("恭喜" + this.userName + "成功登陆FTP服务器");
            isLogin = true;
        } catch (Exception e) {
            LOG.error(this.userName + "登录FTP服务失败！" + e.getMessage());
        }
        this.ftpClient.setBufferSize(1024 * 2);
        this.ftpClient.setDataTimeout(3 * 1000);
        return isLogin;
    }

    /**
     * 退出关闭服务器链接
     */
    public void logOut() {
        if (null != this.ftpClient && this.ftpClient.isConnected()) {
            try {
                boolean reuslt = this.ftpClient.logout();// 退出FTP服务器
                if (reuslt) {
                    if (LOG.isDebugEnabled())
                        LOG.debug("成功退出服务器");
                }
            } catch (IOException e) {
                LOG.error("退出FTP服务器异常！" + e.getMessage());
            } finally {
                try {
                    this.ftpClient.disconnect();// 关闭FTP服务器的连接
                } catch (IOException e) {
                    LOG.error("关闭FTP服务器的连接异常！");
                }
            }
        }
    }

    /**
     * 上传文件
     * 
     * @param localFile
     *            本地文件
     * @param remoteUpLoadePath
     *            上传路径
     * @return
     */
    public boolean uploadFile(String localFile, String remoteUpLoadePath) {
        return uploadFile(new File(localFile), remoteUpLoadePath);
    }

    /***
     * 上传Ftp文件
     * 
     * @param localFile
     *            当地文件
     * @param remoteUpLoadePath上传服务器路径
     *            - 应该以/结束
     * */
    public boolean uploadFile(File localFile, String remoteUpLoadePath) {
        BufferedInputStream inStream = null;
        boolean success = false;
        try {
            inStream = new BufferedInputStream(new FileInputStream(localFile));
            createDirectory(remoteUpLoadePath);
            // 项目集成调用StreamUtil方法来实现
            if (LOG.isDebugEnabled())
                LOG.debug(localFile.getName() + "开始上传.....");
            success = this.ftpClient.storeFile(localFile.getName(), inStream);
            if (success == true) {
                if (LOG.isDebugEnabled())
                    LOG.debug(localFile.getName() + "上传成功");
                return success;
            }
        } catch (FileNotFoundException e) {
            LOG.error(localFile + "未找到");
        } catch (IOException e) {
            LOG.error("上传文件IO出错！" + e.toString());
        } finally {
            if (inStream != null) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return success;
    }
    /***
     * 上传Ftp文件
     * 
     * @param localFile
     *            当地文件
     * @param remoteUpLoadePath上传服务器路径
     *            - 应该以/结束
     * */
    public boolean uploadFile(File localFile, String remoteUpLoadePath,String fileName) {
        BufferedInputStream inStream = null;
        boolean success = false;
        try {
            inStream = new BufferedInputStream(new FileInputStream(localFile));
            createDirectory(remoteUpLoadePath);
            // 项目集成调用StreamUtil方法来实现
            if (LOG.isDebugEnabled())
                LOG.debug(localFile.getName() + "开始上传.....");
            success = this.ftpClient.storeFile(fileName, inStream);
            if (success == true) {
                if (LOG.isDebugEnabled())
                    LOG.debug(localFile.getName() + "上传成功");
                return success;
            }
        } catch (FileNotFoundException e) {
            LOG.error(localFile + "未找到");
        } catch (IOException e) {
            LOG.error("上传文件IO出错！" + e.toString());
        } finally {
            if (inStream != null) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return success;
    }

    /***
     * 上传Ftp文件
     * 
     * @param in
     *            数据流
     * @param remoteUpLoadePath上传服务器路径
     * @param file
     *            存储名称
     * @throws IOException 
     * */
    public boolean uploadFile(String remoteUpLoadePath, String remotefileName, byte[] in) throws IOException {
        InputStream inStream = null;
        boolean success = false;
        try {
            // 项目集成调用StreamUtil方法来实现
            inStream = ByteArrayInputStream(in);
            if (LOG.isDebugEnabled())
                LOG.debug(remotefileName + "开始上传.....");
            this.ftpClient.changeWorkingDirectory(remoteUpLoadePath); //切换到远程目录
            success = this.ftpClient.storeFile(remotefileName, inStream);
            if (success == true) {
                if (LOG.isDebugEnabled())
                    LOG.debug(remotefileName + "上传成功");
                return success;
            }
        } catch (IOException e) {
            LOG.error("上传文件IO出错！" + e.toString());
        } finally {
            if (inStream != null) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return success;
    }
    /***
     * 上传Ftp文件
     * 
     * @param in
     *            数据流
     * @param remoteUpLoadePath上传服务器路径
     * @param file
     *            存储名称
     * @throws IOException 
     * */
    public boolean uploadFile(String remoteUpLoadePath, String remoteFileName, InputStream inStream) throws IOException {
        //InputStream inStream = null;
        boolean success = false;
        try {
            // 项目集成调用StreamUtil方法来实现
            //inStream = ByteArrayInputStream(in);
            if (LOG.isDebugEnabled())
                LOG.debug(remoteFileName + "开始上传.....");
            this.ftpClient.changeWorkingDirectory(remoteUpLoadePath); //切换到远程目录
            success = this.ftpClient.storeFile(new String(remoteFileName.getBytes("GBK") , "iso-8859-1") , inStream);
            if (success == true) {
                if (LOG.isDebugEnabled())
                    LOG.debug(remoteFileName + "上传成功");
                return success;
            }
        } catch (IOException e) {
            LOG.error("上传文件IO出错！" + e.toString());
        } finally {
            if (inStream != null) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return success;
    }
    /**
     * byte 数组 转换流
     * 
     * @param in
     * @return
     */
    private InputStream ByteArrayInputStream(byte[] in) {
        ByteArrayInputStream is = new ByteArrayInputStream(in);
        return is;
    }

    // 项目集成调用StreamUtil方法来实现
    private byte[] input2byte(InputStream inStream) throws IOException {
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[1024];
        int rc = 0;
        while ((rc = inStream.read(buff, 0, 100)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        byte[] in2b = swapStream.toByteArray();
        return in2b;
    }

    /***
     * 下载文件
     * 
     * @param remoteFileName
     *            待下载文件名称
     * @param localDires
     *            下载到当地那个路径下
     * @param remoteDownLoadPath
     *            remoteFileName所在的路径
     * */

    public boolean downloadFile(String localDires, String remoteFileName, String remoteDownLoadPath) {
        String strFilePath = converPath(localDires) + remoteFileName;
        BufferedOutputStream outStream = null;
        boolean success = false;
        try {
            this.ftpClient.changeWorkingDirectory(converPath(remoteDownLoadPath));
            outStream = new BufferedOutputStream(new FileOutputStream(strFilePath));
            if (LOG.isDebugEnabled())
                LOG.debug(remoteFileName + "开始下载....");
            success = this.ftpClient.retrieveFile(remoteFileName, outStream);
            if (success == true) {
                if (LOG.isDebugEnabled())
                    LOG.debug(remoteFileName + "成功下载到" + strFilePath);
                return success;
            }
        } catch (Exception e) {
            LOG.error(remoteFileName + "下载失败");
        } finally {
            if (null != outStream) {
                try {
                    outStream.flush();
                    outStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        if (success == false) {
            if (LOG.isDebugEnabled())
                LOG.debug(remoteFileName + "下载失败!!!");
        }
        return success;
    }

    /***
     * 下载文件
     * 
     * @param remoteFileName
     *            待下载文件名称
     * @param localDires
     *            下载到当地那个路径下
     * @param remoteDownLoadPath
     *            remoteFileName所在的路径
     * @throws IOException
     * */

    public byte[] downloadFile(String remoteFileName, String remoteDownLoadPath) throws IOException {
        InputStream inStream = null;
        byte[] retBytes = null;
        try {
            // Properties prop = System.getProperties();
            // String os = prop.getProperty("os.name");
            // if(os.startsWith("win") || os.startsWith("Win")){
            // remoteDownLoadPath = remoteDownLoadPath.replace("\\","/");
            // }
            // boolean b=ftpClient.changeWorkingDirectory("/2016");
            this.ftpClient.changeWorkingDirectory(remoteDownLoadPath.trim());
            if (LOG.isDebugEnabled())
                LOG.debug(remoteFileName + "开始下载....");
            inStream = this.ftpClient.retrieveFileStream(remoteFileName.trim());
            retBytes = input2byte(inStream);
        } catch (Exception e) {
            LOG.error(remoteFileName + "下载失败");
        } finally {
            if (null != inStream) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return retBytes;
    }

    /***
     * @上传文件夹
     * @param localDirectory
     *            当地文件夹
     * @param remoteDirectoryPath
     *            Ftp 服务器路径 以目录"/"结束
     * @throws IOException
     * @throws UnsupportedEncodingException
     * */
    public boolean uploadDirectory(String localDirectory, String remoteDirectoryPath)
            throws UnsupportedEncodingException, IOException {
        File src = new File(localDirectory);

        File[] allFile = src.listFiles();
        for (int currentFile = 0; currentFile < allFile.length; currentFile++) {
            if (!allFile[currentFile].isDirectory()) {
                String srcName = allFile[currentFile].getPath().toString();
                uploadFile(new File(srcName), remoteDirectoryPath);
            }
        }
        for (int currentFile = 0; currentFile < allFile.length; currentFile++) {
            if (allFile[currentFile].isDirectory()) {
                // 递归
                String path = converPath(remoteDirectoryPath) + allFile[currentFile].getName();
                createDirectory(allFile[currentFile].getName().toString());
                uploadDirectory(allFile[currentFile].getPath().toString(), path);
            }
        }
        return true;
    }

    /***
     * @下载文件夹
     * @param localDirectoryPath本地地址
     * @param remoteDirectory
     *            远程文件夹
     * */
    public boolean downLoadDirectory(String localDirectoryPath, String remoteDirectory) {
        remoteDirectory = converPath(remoteDirectory);
        localDirectoryPath = converPath(localDirectoryPath);
        try {
            new File(localDirectoryPath).mkdirs();
            FTPFile[] allFile = this.ftpClient.listFiles(remoteDirectory);
            for (int currentFile = 0; currentFile < allFile.length; currentFile++) {
                if (!allFile[currentFile].isDirectory()) {
                    downloadFile(allFile[currentFile].getName(), localDirectoryPath, remoteDirectory);
                }
            }
            for (int currentFile = 0; currentFile < allFile.length; currentFile++) {
                if (allFile[currentFile].isDirectory()) {
                    String strRemoteDirectoryPath = converPath(remoteDirectory) + allFile[currentFile].getName();
                    String strLocalDirectoryPath = converPath(localDirectoryPath) + allFile[currentFile].getName();
                    new File(converPath(strLocalDirectoryPath)).mkdirs();
                    // this.ftpClient.changeWorkingDirectory(converPath(strRemoteDirectoryPath));
                    downLoadDirectory(converPath(strLocalDirectoryPath), converPath(strRemoteDirectoryPath));
                }
            }
        } catch (IOException e) {
            LOG.error("下载文件夹失败!" + e.toString());
            return false;
        }
        return true;
    }

    /**
     * 根据路径进行创建文件，解决兼容问题
     * 
     * @param path
     * @return
     * @throws IOException
     * @throws UnsupportedEncodingException
     */
    public boolean createDirectory(String path) throws UnsupportedEncodingException, IOException {
        path = converPath(path);
        String directory = path.substring(0, path.lastIndexOf("/") + 1);
        if (!directory.equalsIgnoreCase("/") && !this.ftpClient.changeWorkingDirectory(directory)) {
            // 如果远程目录不存在，则递归创建远程服务器目录
            int start = 0;
            int end = 0;
            if (directory.startsWith("/")) {
                start = 1;
            } else {
                start = 0;
            }
            end = directory.indexOf("/", start);
            while (true) {
                String subDirectory = path.substring(start, end);
                if (!ftpClient.changeWorkingDirectory(subDirectory)) {
                    if (ftpClient.makeDirectory(subDirectory)) {
                        ftpClient.changeWorkingDirectory(subDirectory);
                    } else {
                        if (LOG.isDebugEnabled())
                            LOG.debug("创建目录失败!");
                        return false;
                    }
                }
                start = end + 1;
                end = directory.indexOf("/", start);
                // 检查所有目录是否创建完毕
                if (end <= start) {
                    break;
                }
            }
        }
        return true;
    }

    /**
     * 增加目录结尾标识“/”
     * 
     * @param path
     * @return
     */
    private String converPath(String path) {
        if (!path.trim().endsWith("/"))
            path = path + "/";
        return path;
    }

    /**
     * 读取图片 文件
     * 
     * @param imgPath
     * @return
     */
    public static byte[] imageToByteArray(String imgPath) {
        BufferedInputStream in;
        try {
            in = new BufferedInputStream(new FileInputStream(imgPath));
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int size = 0;
            byte[] temp = new byte[1024];
            while ((size = in.read(temp)) != -1) {
                out.write(temp, 0, size);
            }
            in.close();
            return out.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据日期转换为路径 目录到分钟
     * 
     * @return
     */
    public String sysDate2path2minute() {
        Calendar date = Calendar.getInstance();
        String rootDir = "";
        String path = rootDir + "/" + date.get(Calendar.YEAR) + "/" + (date.get(Calendar.MONTH) + 1) + "/"
                + date.get(Calendar.DAY_OF_MONTH) + "/" + date.get(Calendar.HOUR_OF_DAY) + "/"
                + date.get(Calendar.MINUTE);
        return path;
    }

    /**
     * 根据日期转换为路径 目录到小时
     * 
     * @return
     */
    public String sysDate2path2hour() {
        Calendar date = Calendar.getInstance();
        String rootDir = "";
        String path = rootDir + "/" + date.get(Calendar.YEAR) + "/" + (date.get(Calendar.MONTH) + 1) + "/"
                + date.get(Calendar.DAY_OF_MONTH) + "/" + date.get(Calendar.HOUR_OF_DAY);
        return path;
    }

    /**
     * 根据日期转换为路径 目录到天
     * 
     * @return
     */
    public String sysDate2path2day() {
        Calendar date = Calendar.getInstance();
        String rootDir = "";
        String path = rootDir + "/" + date.get(Calendar.YEAR) + "/" + (date.get(Calendar.MONTH) + 1) + "/"
                + date.get(Calendar.DAY_OF_MONTH);
        return path;
    }
    
    /**
     * * 删除文件 *
     * 
     * @param remoteUpLoadePath
     *            FTP服务器保存目录 *
     * @param remoteFileName
     *            要删除的文件名称 *
     * @return
     */
    public boolean deleteFile(String remoteUpLoadePath, String remoteFileName) {
        boolean flag = false;
        try {
            //切换FTP目录
            this.ftpClient.changeWorkingDirectory(remoteUpLoadePath);
            //删除
            this.ftpClient.dele(remoteFileName);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return flag;
    }


    public static void main(String[] args) throws FileNotFoundException {

        long start = System.currentTimeMillis();
        FtpUtil ftp = new FtpUtil("114.242.131.213", 21, "CICLTEST", "CICLTEST");
        ftp.login();
        File file = new File("D:\\lnh.log");
//        InputStream is = new FileInputStream(file);

        ftp.uploadFile(file, "/ftp", "lnh.log");
        ftp.downLoadDirectory("D:\\111.xlsx", "/ftp");
        ftp.logOut();
        System.out.println("传输完成！");
        long end = System.currentTimeMillis();
        System.out.println("总时间毫秒：" + (end - start));
        
        
    }
}